package com.client.controller.auth;

import com.client.Initialize;
import com.client.entity.B_client;
import com.client.mapper.MessageDao;
import com.client.mapper.PassAuthorDao;
import com.client.service.*;
import com.client.sm9.gm.sm9.G1KeyPair;
import com.client.utils.MessageUtils;
import com.client.utils.UDPUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.integration.annotation.Poller;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.stereotype.Component;

import java.sql.Timestamp;
import java.util.Date;
import java.util.Map;
import java.util.Random;
import java.util.UUID;

@Slf4j
@Component
public class CertificationController {
    @Autowired
    Sm9Service userService;
    @Autowired
    Certification certification;
    @Autowired
    ExchangeService exchangeService;
    @Autowired
    KeyService keyService;
    @Autowired
    UDPUtil udp;
    @Autowired
    PassAuthorDao passAuthorDao;
    @Autowired
    MessageService messageService;
    @Autowired
    MigrationService migrationService;

    @Autowired
    MessageDao messageDao;


    @Value("${udp.receive}")
    private Integer port;

    @ServiceActivator(inputChannel = "certification1")
    public void udpMessageHandle1(Map<String, Object> map, @Headers Map<String, Object> headers) {
        String id = (String) map.get("id");
        if (messageService.newClient((UUID)map.get("uid"), id, (Integer) map.get("port"), (String) headers.get("ip_address"))) {
            log.info("收到[" + id + "]的认证请求1，已加入认证列表");
            B_client client = messageService.getClient(id);


            updateTime((Date) map.get("time"),client,map);

            int my_n = new Random().nextInt(10000);
            client.setMy_n(my_n);
            byte[] bytes = null;

            try {
                bytes = certification.send2(id, my_n, client);

            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!Initialize.HPS)
                send(client, bytes);
            client.setFlag(2);
        } else {
            log.info("收到[" + id + "]的认证请求1，但认证列表已经存在该对象");
        }
    }

    @ServiceActivator(inputChannel = "certification2")
    public void udpMessageHandle2(Map<String, Object> map, @Headers Map<String, Object> headers) {
        String id = (String) map.get("id");
        B_client client = messageService.getClient(id);
        if (client != null && client.getFlag() == 1) {
            log.info("收到[" + id + "]的认证请求2，已记录");

            String goal_ip = client.getGoal_ip();
            int goal_port = client.getGoal_port();
            int goal_n = (Integer) map.get("n");
            client.setGoal_n(goal_n);

            updateTime((Date) map.get("time"),client,map);

            byte[] bytes = null;

            try {
                bytes = certification.send3(id, goal_n, client.getMy_n(),client.getUid());
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!Initialize.HPS)
                send(client, bytes);
            client.setFlag(3);
        } else if (client == null) {
            log.info("收到[" + id + "]的认证请求2，但认证列表不存在该对象");
        } else if (client.getFlag() > 1) {
            log.info("收到[" + id + "]的认证请求2，但该对象已完成这步流程，目前处于状态[{}]", client.getFlag());
        }
    }

    @ServiceActivator(inputChannel = "certification3")
    public void udpMessageHandle3(Map<String, Object> map, @Headers Map<String, Object> headers) {
        String id = (String) map.get("id");
        B_client client = messageService.getClient(id);
        if (client != null && client.getFlag() == 2) {
            log.info("收到[" + id + "]的认证请求3，已记录");
            updateTime((Date) map.get("time"),client,map);

            String goal_ip = client.getGoal_ip();
            int goal_port = client.getGoal_port();
            byte[] bytes = null;

            int f_n = (Integer) map.get("f_n");
            if (f_n == client.getMy_n() % 25) {
                log.info("[" + id + "]的认证成功：成功答出经变换后的n值");
                client.setFlag(-2);//认证成功
            } else {
                //认证失败
                client.setFlag(-1);
                log.info("[" + id + "]的认证失败：未成功答出经变换后的n值");
                return;
            }

            try {
                bytes = certification.send4(id, (Integer) map.get("n"),client.getUid());
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!Initialize.HPS)
                send(client, bytes);
        } else if (client == null) {
            log.info("收到[" + id + "]的认证请求3，但认证列表不存在该对象");
        } else if (client.getFlag() > 2) {
            log.info("收到[" + id + "]的认证请求3，但该对象已完成这步流程，目前处于状态[{}]", client.getFlag());
        } else if (client.getFlag() < 2) {
            log.info("收到[" + id + "]的认证请求3，但该对象之前流程尚未认证完毕，目前处于状态[{}]", client.getFlag());
        }
    }

    @ServiceActivator(inputChannel = "certification4")
    public void udpMessageHandle4(Map<String, Object> map) {
        String id = (String) map.get("id");
        B_client client = messageService.getClient(id);
        if (client != null && client.getFlag() == 3) {
            log.info("收到[" + id + "]的认证请求4，已记录");
            updateTime((Date) map.get("time"),client,map);

            String goal_ip = client.getGoal_ip();
            int goal_port = client.getGoal_port();
            byte[] bytes = null;

            int f_n = (Integer) map.get("f_n");
            if (f_n == client.getMy_n() % 25) {
                log.info("[" + id + "]的认证成功：成功答出经变换后的n值。对方也确认了我们的身份");
                client.setFlag(-2);//认证成功
            } else {
                //认证失败
                client.setFlag(-1);
                log.info("[" + id + "]的认证失败：未成功答出经变换后的n值");
                return;
            }

            try {
                bytes = certification.send5(id,client.getUid());
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!Initialize.HPS)
                send(client, bytes);
            log.info("[" + id + "]的认证成功，我们已将此消息告知对方，接下来可开始正常通信");
        } else if (client == null) {
            log.info("收到[" + id + "]的认证请求4，但认证列表不存在该对象");
        } else if (client.getFlag() > 3) {
            log.info("收到[" + id + "]的认证请求4，但该对象已完成这步流程，目前处于状态[{}]", client.getFlag());
        } else if (client.getFlag() < 3) {
            log.info("收到[" + id + "]的认证请求4，但该对象之前流程尚未认证完毕，目前处于状态[{}]", client.getFlag());
        }
    }

    @ServiceActivator(inputChannel = "certification5")
    public void udpMessageHandle5(Map<String, Object> map, @Headers Map<String, Object> headers) {
        String id = (String) map.get("id");
        B_client client = messageService.getClient(id);
        if (client != null && client.getFlag() == -2) {
            log.info("收到[" + id + "]的认证请求5，对方已知道我们将其确认，接下来可开展正常通信");
            updateTime((Date) map.get("time"),client,map);
            //发起密钥交换
            client.setSponsor(true);
            G1KeyPair g1KeyPair = exchangeService.Exchange1(client);
            if (!Initialize.HPS) {
                //修改状态
                client.setMyKeyPair(g1KeyPair);

                byte[] body_b = exchangeService.exchange1(client);
                //发送udp包
                send(client, body_b);
                log.info("发送密钥交换1");
                //修改状态
                client.setExchang_flag(1);

            }
            client.setSponsor(true);

        } else if (client == null) {
            log.info("收到[" + id + "]的认证请求5，但认证列表不存在该对象");
        }
    }

    public void send(B_client client,byte[] msg){
        MessageService.addMessage(client.getUid().toString(),client.getGoal_ip(),client.getGoal_port(),msg,
                MessageUtils.getNowTime(),8,30);
        udp.send(client.getGoal_ip(),client.getGoal_port(),msg);

    }
    public void updateTime(Date time,B_client client,Map<String, Object> map){
        MessageService.deleteMessage(client.getUid().toString());
        client.setTime(time);
        messageDao.add(client.getGoal_id(),keyService.getId(),client.getGoal_ip(),client.getGoal_port(),client.getUid().toString(),map.get("uuid").toString(),
                0,map.get("type").toString(),new Timestamp(MessageUtils.getNowTime().getTime()));
    }
}
